#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define DEV_CNT         1
#define GPIO41_NAME     "gpio41"
#define beep_on         1
#define beep_off        0

struct gpio41_dev
{
    dev_t devid;                  /* 设备号 */
    struct cdev cdev;             /* cdev */
    struct class *class;          /* 类 */
    struct device *device;        /* 设备 */
    int major;                    /* 主设备号 */
    int minor;                    /* 次设备号 */
    struct device_node *nd;       /* 设备节点 */
    int gpio41;
};

struct gpio41_dev gpio41;
static int gpio41_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &gpio41;
    return 0;
}

static ssize_t gpio41_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}

static ssize_t gpio41_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    int ret;
    unsigned char databuf[1];
    unsigned char beepsta;

    struct  gpio41_dev *dev =filp->private_data;

    ret = copy_from_user(databuf, buf, cnt);
    if(ret < 0)
    {
        printk("kernel write failed!\r\n");
        return -1;
    }
    
    if(databuf[0] == beep_on)
    {
        gpio_set_value(dev->gpio41, beepsta);
    }
    else if(databuf[0] == beep_off)
    {
        gpio_set_value(dev->gpio41, beepsta);
    }
    return 0;
}

static int gpio41_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static struct file_operations gpio41_fops =
{
    .owner = THIS_MODULE,
    .open = gpio41_open,
    .read = gpio41_read,
    .write = gpio41_write,
    .release = gpio41_release,
};

static int __init gpio41_init(void)
{

    int ret = 0;
    gpio41.nd= of_find_node_by_path("/gpio41");
    if(gpio41.nd == NULL)
    {
        printk("gpio41 node not find!\r\n");
        return -1;
    }
    gpio41.gpio41=of_get_named_gpio(gpio41.nd,GPIO41_NAME,0);
    if(gpio41.gpio41<0)
    {
        printk("gpio41 node not find!\r\n");
        return -1;
    }
    ret=gpio_direction_output(gpio41.gpio41,1);

    ret=alloc_chrdev_region(&gpio41.devid,0,DEV_CNT,GPIO41_NAME);
    if(ret<0)
    {
        printk("alloc_chrdev_region failed!\r\n");
        return -1;
    }
    gpio41.major=MAJOR(gpio41.devid);
    gpio41.minor=MINOR(gpio41.devid);
    printk("gpio41_major=%d,gpio41_minor=%d\r\n",gpio41.major,gpio41.minor);

    gpio41.cdev.owner=THIS_MODULE;
    cdev_init(&gpio41.cdev,&gpio41_fops);
    ret=cdev_add(&gpio41.cdev,gpio41.devid,DEV_CNT);
    if(ret<0)
    {
        printk("cdev_add failed!\r\n");
        unregister_chrdev_region(gpio41.devid,DEV_CNT);
        return -1;
    }
    gpio41.class=class_create(THIS_MODULE,"gpio41dev");
    if(IS_ERR(gpio41.class))
    {
        printk("class_create failed!\r\n");
        cdev_del(&gpio41.cdev);
        unregister_chrdev_region(gpio41.devid,DEV_CNT);
        return -1;
    }
    gpio41.device=device_create(gpio41.class,NULL,gpio41.devid,NULL,"gpio41dev");
    if(IS_ERR(gpio41.device))
    {
        printk("device_create failed!\r\n");
        class_destroy(gpio41.class);
        cdev_del(&gpio41.cdev);
        unregister_chrdev_region(gpio41.devid,DEV_CNT);
        return -1;
    }

    return 0;

}